using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Plugin;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace SoapConnector
{
    [Icon("pack://application:,,,/SoapConnector;component/Resources/Icon.png")]
    [Designer("SoapConnector.Designer.SoapConnectorServerCommandDesigner, SoapConnector")]
    public class SoapConnectorServerCommand : Command, ICommandExecutableInServerSideAsync
    {
        [FormulaProperty]
        [DisplayName("服务地址(EndPoint URL)")]
        [Required]
        public object EndPointUrl { get; set; }

        [FormulaProperty]
        [DisplayName("方法名(Action)")]
        public object ActionName { get; set; }
        
        [DisplayName("用户鉴权(Authorization)")]
        [Description("开启用户鉴权，当前版本仅支持 Basic 模式。开启鉴权后，插件会自动向 Headers 插入鉴权信息")]
        public bool EnableAuth { get; set; }
        
        [FormulaProperty]
        [DisplayName("用户名(Username)")]
        [Required]
        public object Username { get; set; }

        [FormulaProperty]
        [DisplayName("密码(Password)")]
        public object Password { get; set; }
        
        [ListProperty]
        [DisplayName("请求头参数(Headers)")]
        [Description("面向 Web Service 本身的 HTTP 请求头配置。SOAP Header请配置在请求体参数(body)中")]
        public List<HeaderParameter> RequestHeaders { get; set; }
        
        [ListProperty]
        [DisplayName("请求体参数(body)")]
        [Description("每一项对应xml中的一个标签，系统会按照顺序自动组装成完整的请求body")]
        public List<XmlParameter> RequestBodyParams { get; set; }

        [ResultToProperty]
        [DisplayName("请求结果")]
        public string ResultTo { get; set; } = "resp";
        
        private static readonly HashSet<string> AuthProperties =
        [
            nameof(Username),
            nameof(Password)
        ];
        
        public override bool GetDesignerPropertyVisible(string propertyName, CommandScope commandScope)
        {
            return AuthProperties.Contains(propertyName)
                ? EnableAuth
                : base.GetDesignerPropertyVisible(propertyName, commandScope);
        }

        public async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var endpoint = await dataContext.EvaluateFormulaAsync(EndPointUrl);
            
            using var client = new HttpClient();
            
            if (RequestHeaders is { Count: > 0 })
            {
                var headerBuilder = new StringBuilder();
                foreach (var param in RequestHeaders)
                {
                    var paramNameObj = await dataContext.EvaluateFormulaAsync(param.ParamName);
                    if (paramNameObj is not string paramName || string.IsNullOrWhiteSpace(paramName))
                    {
                        continue;
                    }

                    var paramValueObj = await dataContext.EvaluateFormulaAsync(param.ParamValue);
                    var paramValue = paramValueObj?.ToString() ?? string.Empty;

                    // 避免重复添加相同的 header
                    if (!client.DefaultRequestHeaders.Contains(paramName))
                    {
                        client.DefaultRequestHeaders.Add(paramName, paramValue);
                    }
                }
            }

            if (EnableAuth)
            {
                var username = await dataContext.EvaluateFormulaAsync(Username);
                var password = await dataContext.EvaluateFormulaAsync(Password);
                var credentials = $"{username}:{password}";
                var base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
                
                const string authHeader = "Authorization";
                var authValue = $"Basic {base64Credentials}";

                // 如果已存在，先移除再添加，保证不会重复
                if (client.DefaultRequestHeaders.Contains(authHeader))
                {
                    client.DefaultRequestHeaders.Remove(authHeader);
                }

                client.DefaultRequestHeaders.Add(authHeader, authValue);
            }
            
            // 日志输出
            if (client.DefaultRequestHeaders.Any())
            {
                var headerLog = new StringBuilder("请求 Headers：");
                foreach (var header in client.DefaultRequestHeaders)
                {
                    // 可能一个 header 有多个值，用 string.Join 拼接
                    headerLog.AppendLine($"{header.Key}: {string.Join(",", header.Value)}");
                }
                dataContext.Log.AppendLine(headerLog.ToString());
            }
            
            // 2. 组装 SOAP Body
            var soapBody = "";
            if (RequestBodyParams is { Count: > 0 })
            {
                var bodyBuilder = new StringBuilder();
                foreach (var param in RequestBodyParams)
                {
                    var paramValue = await dataContext.EvaluateFormulaAsync(param.XmlLabel);
                    bodyBuilder.AppendLine($"{paramValue}");
                }

                soapBody = bodyBuilder.ToString();
            }
            dataContext.Log.AppendLine("SOAP Body：" + soapBody);

            
            var content = new StringContent(soapBody, Encoding.UTF8, "text/xml");

            // SOAPAction 是必须的（有的服务要求）
            var action = await dataContext.EvaluateFormulaAsync(ActionName);
            if (action !=null  && !string.IsNullOrWhiteSpace(action.ToString()))
            {
                if (client.DefaultRequestHeaders.Contains("SOAPAction"))
                {
                    client.DefaultRequestHeaders.Remove("SOAPAction");
                }
                client.DefaultRequestHeaders.Add("SOAPAction", ActionName.ToString());
            }
            
            try
            {
                // 4. 发送 POST 请求
                var response = await client.PostAsync(endpoint.ToString(), content);

                var responseText = await response.Content.ReadAsStringAsync();

                // 打印日志
                dataContext.Log.AppendLine($"响应状态：{response.StatusCode}");

                dataContext.Parameters[ResultTo] = responseText;
            }
            catch (Exception ex)
            {
                dataContext.Log.AppendLine("请求异常：" + ex.Message);
                dataContext.Parameters[ResultTo] = $"请求异常：{ex.Message}";
                
            }
            return new ExecuteResult();
        }

        public override string ToString()
        {
            return "Web Service 请求(SOAP)";
        }

        public override CommandScope GetCommandScope()
        {
            return CommandScope.ExecutableInServer;
        }

        public class XmlParameter : ObjectPropertyBase
        {
            [FormulaProperty]
            [DisplayName("请求参数标签项")]
            [ListPropertyItemSetting(DefaultWidth = 400)]
            public object XmlLabel { get; set; }
        }
        
        public class HeaderParameter : ObjectPropertyBase
        {
            [FormulaProperty]
            [DisplayName("参数名")]
            [ListPropertyItemSetting(DefaultWidth = 200)]
            public object ParamName { get; set; }
            
            [FormulaProperty]
            [DisplayName("参数值")]
            [ListPropertyItemSetting(DefaultWidth = 200)]
            public object ParamValue { get; set; }
        }
        
    }
}
